package com.efun.center.config;

import com.efun.center.datasource.DataSourceMap;
import com.efun.center.datasource.DynamicDataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Properties;

@Configuration
public class DataSourceConfiguration implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private ConfigurableEnvironment environment;

    @SuppressWarnings("rawtypes")
	@Override
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment) environment;

        // 加载指定数据库信息文件
        try {
            Resource resource = new DefaultResourceLoader().getResource(environment.getProperty("spring.config.location"));
            Properties jdbcProperties = new Properties();
            jdbcProperties.load(resource.getInputStream());
            PropertySource propertySource = new PropertiesPropertySource("Properteis", jdbcProperties);
            this.environment.getPropertySources().addFirst(propertySource);
        } catch (IOException e) {
            e.printStackTrace();
        }

        EfunConfiguration.httpProfile = environment.getProperty("efun.http.profile");
        logger.info("efun.http.profile=" + EfunConfiguration.httpProfile);
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 生成数据库连接池信息
        ManagedMap<String, RuntimeBeanReference> targetDataSources = new ManagedMap<String, RuntimeBeanReference>();
        BeanDefinitionBuilder beanDefinitionBuilder = null;
        BeanDefinition beanDefinition = null;
        for (DataSourceMap datasource : DataSourceMap.values()) {
            String jdbcUrl = environment.getProperty("spring.datasource." + datasource + ".url");
            jdbcUrl += "?useSSL=false&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&autoReconnect=true";
            String username = environment.getProperty("spring.datasource." + datasource + ".username");
            String password = environment.getProperty("spring.datasource." + datasource + ".password");
            if (StringUtils.isEmpty(jdbcUrl) || StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
                continue;
            }
            beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(HikariDataSource.class);
            setDefaultProperty(beanDefinitionBuilder);
            beanDefinitionBuilder.addPropertyValue("jdbcUrl", environment.resolvePlaceholders(jdbcUrl));
            beanDefinitionBuilder.addPropertyValue("username", environment.resolvePlaceholders(username));
            beanDefinitionBuilder.addPropertyValue("password", environment.resolvePlaceholders(password));
            beanDefinition = beanDefinitionBuilder.getBeanDefinition();
            registry.registerBeanDefinition(datasource.name(), beanDefinition);
            targetDataSources.put(datasource.name(), new RuntimeBeanReference(datasource.name()));
            logger.info("datasource [" + datasource.name() + "] load success!");
        }
        beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(DynamicDataSource.class);
        beanDefinitionBuilder.addPropertyValue("targetDataSources", targetDataSources);
        beanDefinitionBuilder.addPropertyReference("defaultTargetDataSource", DataSourceMap.manager.name());
        beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        beanDefinition.setPrimary(true);
        beanDefinition.setAttribute("id", "routingDataSource");
        registry.registerBeanDefinition("routingDataSource", beanDefinition);
    }

    private void setDefaultProperty(BeanDefinitionBuilder beanDefinitionBuilder) {
        beanDefinitionBuilder.setDestroyMethodName("close");
        beanDefinitionBuilder.addPropertyValue("connectionTimeout", "60000");
        beanDefinitionBuilder.addPropertyValue("maxLifetime", "1800000");
        beanDefinitionBuilder.addPropertyValue("maximumPoolSize", "10");
        beanDefinitionBuilder.addPropertyValue("readOnly", "false");
    }

}
